using System;
using System.Collections.Generic;
using System.Text;

namespace LibGreen.Jabber
{
    /// <summary>
    /// Describes the parts of a JID:  node@domain/resource
    /// </summary>
    public enum JidPart
    {
        /// <summary>
        /// The node portion of a JID
        /// </summary>
        Node,
        /// <summary>
        /// The domain portion of a JID
        /// </summary>
        Domain,
        /// <summary>
        /// The resource portion of a JID
        /// </summary>
        Resource,
    }

    /// <summary>
    /// Encapsulates a Jabber ID (JID)
    /// </summary>
    public class Jid : IComparable
    {
        /// <summary>
        /// Retrieves a single section of a JID
        /// </summary>
        /// <param name="jid">The JID to parse</param>
        /// <param name="part">The part of the JID to return</param>
        /// <returns>The requested section of the JID</returns>
        public static string GetJidSection(string jid, JidPart part)
        {
            Jid id = new Jid(jid);
            switch (part)
            {
                case JidPart.Node:
                    return id.Node;
                case JidPart.Domain:
                    return id.Domain;
                case JidPart.Resource:
                    return id.Resource;
            }
            return "";
        }

        private readonly string node;
        private readonly string domain;
        private string resource;

        /// <summary>
        /// Initializes a new JID without a resource
        /// </summary>
        /// <param name="node">The node portion of the JID</param>
        /// <param name="domain">The domain portion of the JID</param>
        public Jid(string node, string domain)
            : this(node, domain, "")
        {
        }

        /// <summary>
        /// Initializes a new Jid with a named resource
        /// </summary>
        /// <param name="node">The node portion of the JID</param>
        /// <param name="domain">The domain portion of the JID</param>
        /// <param name="resource">The resource portion of the JID</param>
        public Jid(string node, string domain, string resource)
        {
            this.node = node;
            this.domain = domain;
            this.resource = resource;
        }

        /// <summary>
        /// Initializes a new Jid from a received JID string
        /// </summary>
        /// <param name="jid">A received JID string</param>
        public Jid(string jid)
        {
            string[] parts = jid.Split('@');
            string domainressplit = "";
            if (parts.Length > 1)
            {
                this.node = parts[0];
                domainressplit = parts[1];
            }
            else
            {
                domainressplit = parts[0];
            }
            parts = domainressplit.Split('/');
            this.domain = parts[0];
            if (parts.Length > 1)
            {
                this.resource = parts[1];
            }
        }

        /// <summary>
        /// Gets the node portion of the JID
        /// </summary>
        public string Node
        {
            get { return node; }
        }

        /// <summary>
        /// Gets the domain portion of the JID
        /// </summary>
        public string Domain
        {
            get { return domain; }
        }

        /// <summary>
        /// Gets the resource portion of the JID
        /// </summary>
        public string Resource
        {
            get { return resource; }
            internal set { resource = value; }
        }

        /// <summary>
        /// Gets a string representation of the JID
        /// </summary>
        /// <returns>A string representation of the JID</returns>
        public override string ToString()
        {
            return ToString(true);
        }

        /// <summary>
        /// Gets a string representation of the JID, optionally including the resource section
        /// </summary>
        /// <param name="includeResource">A value indicating whether the resource section (if present) should be included</param>
        /// <returns>A string representation of the JID</returns>
        public string ToString(bool includeResource)
        {
            if (!includeResource || String.IsNullOrEmpty(resource))
            {
                return String.Format("{0}@{1}", node, domain);
            }
            return String.Format("{0}@{1}/{2}", node, domain, resource);
        }

        #region IComparable Members
        /// <summary>
        /// Compares the current instance with another object of the same type.
        /// </summary>
        /// <param name="obj">An object to compare with this instance.</param>
        /// <returns>A 32-bit signed integer that indicates the relative order of the objects being compared.</returns>
        public int CompareTo(object obj)
        {
            Jid other = obj as Jid;
            if (other != null)
            {
                return ToString().CompareTo(other.ToString());
            }
            return -1;
        }

        /// <summary>
        /// Determines whether the specified Object is equal to the current Object.
        /// </summary>
        /// <param name="obj">The Object to compare with the current Object.</param>
        /// <returns>true if the specified Object is equal to the current Object; otherwise, false.</returns>
        public override bool Equals(object obj)
        {
            return CompareTo(obj) == 0;
        }

        /// <summary>
        /// Serves as a hash function for a particular type.
        /// </summary>
        /// <returns>A hash code for the current object</returns>
        public override int GetHashCode()
        {
            return ToString().GetHashCode();
        }

        #endregion
    }
}
